package com.clp.protocol.modbus_tcp.mb_frame.mb_head;

import com.clp.protocol.core.common.frame.InitializableFrameClip;
import com.clp.protocol.core.utils.ByteUtil;
import com.clp.protocol.modbus_tcp.definition.ConstVal;
import com.clp.protocol.modbus_tcp.definition.MbByteOrder;
import com.clp.protocol.modbus_tcp.definition.Tag;
import io.netty.buffer.ByteBuf;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;

import java.nio.ByteOrder;
import java.util.Objects;

@Getter
@NoArgsConstructor
@AllArgsConstructor
public class MbHead implements InitializableFrameClip<MbHead> {
    /**
     * 事务处理标识符（2字节），用于区分每次的消息
     */
    private int seq;

    /**
     * 协议标识符（2字节），00 00 代表TCP协议
     */
    private Tag tag;

    /**
     * 长度
     */
    private int len;


    @Override
    public MbHead initBy(ByteBuf buf) {
        // 1、获取事务处理标识符
        this.seq = MbByteOrder.seqOrder == ByteOrder.BIG_ENDIAN ? (buf.readShort() & 0xFF) : (buf.readShortLE() & 0xFF);
        // 2、获取协议标识符
        byte[] tagBytes = new byte[ConstVal.TAG_LEN]; buf.readBytes(tagBytes);
        this.tag = Tag.gain(tagBytes);
        // 3、获取长度
        this.len = MbByteOrder.lenOrder == ByteOrder.BIG_ENDIAN ? (buf.readShort() & 0xFF) : (buf.readShortLE() & 0xFF);
        return this;
    }

    @Override
    public boolean isValid() {
        if (seq < 0 || seq > 0xFFFF) return false;
        return tag != null;
    }

    @Override
    public void writeTo(ByteBuf buf) {
        // 事务处理标识符
        buf.writeBytes(MbByteOrder.seqOrder == ByteOrder.BIG_ENDIAN ?
                (ByteUtil.intToBytes2BE(seq)) : (ByteUtil.intToBytes2LE(seq)));
        // 协议标识符
        buf.writeBytes(tag.getBytes());
        // 长度
        buf.writeBytes(MbByteOrder.lenOrder == ByteOrder.BIG_ENDIAN ?
                (ByteUtil.intToBytes2BE(len)) : (ByteUtil.intToBytes2LE(len)));
    }

    @Override
    public String toString() {
        return "序号：" + seq + ", 协议类型：" + tag + ", 字节长度：" + len;
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        MbHead mbHead = (MbHead) o;
        return seq == mbHead.seq && len == mbHead.len && tag == mbHead.tag;
    }

    @Override
    public int hashCode() {
        return Objects.hash(seq, tag, len);
    }
}
